package com.hd123.rumba.gwt.widget2.client.panel;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.MouseOutEvent;
import com.google.gwt.event.dom.client.MouseOutHandler;
import com.google.gwt.event.dom.client.MouseOverEvent;
import com.google.gwt.event.dom.client.MouseOverHandler;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Focusable;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.hd123.rumba.gwt.util.client.MessageRecord;

/**
 * 消息面板
 * <p>
 * 用于界面上的提示信息显示，消息的级别一般包括：提示、警告、错误等。
 * 
 * @author LiQi
 */
public class RMessagePanel extends Composite {

  /** 消息级别 */
  public static final int LEVEL_INFO = MessageRecord.LEVEL_INFO;
  public static final int LEVEL_WARNING = MessageRecord.LEVEL_WARNING;
  public static final int LEVEL_ERROR = MessageRecord.LEVEL_ERROR;

  /** 样式 */
  private static final String STYLENAME = "rb-MessagePanel";
  private static final String STYLENAME_MESSAGE = "rb-MessagePanel-message";
  private static final String STYLENAME_MESSAGE_HASFOCUSWIDGET = "rb-MessagePanel-message-hasfocuswidget";
  private static final String STYLENAME_MESSAGE_HASFOCUSWIDGET_HOVER = "rb-MessagePanel-message-hasfocuswidget-hover";

  private static final String IMAGE_INFO = "images/panel/info.gif";
  private static final String IMAGE_WARNING = "images/panel/warning.gif";
  private static final String IMAGE_ERROR = "images/panel/error.gif";
  private static final String IMAGE_CLOSEBUTTON = "images/panel/close2.gif";

  /** 各级别消息面板的容器 */
  private VerticalPanel levelsPanel;

  /** 各级别消息面板 */
  private VerticalPanel infoPanel, warningPanel, errorPanel;

  /** 消息列表 */
  private List/*<RMessagePanel.Message>*/messages;

  /** 消息条目事件处理 */
  private MessageItemHandler messageItemHandler;

  public RMessagePanel() {
    super();

    messages = new ArrayList();
    messageItemHandler = new MessageItemHandler();

    HorizontalPanel root = new HorizontalPanel();
    root.setWidth("100%");
    root.setSpacing(3);
    root.setStyleName(STYLENAME);

    levelsPanel = new VerticalPanel();
    root.add(levelsPanel);

    Image closeButton = new Image(IMAGE_CLOSEBUTTON, 0, 0, 18, 18);
    DOM.setStyleAttribute(closeButton.getElement(), "cursor", "hand");
    CloseButtonHandler closeButtonHandler = new CloseButtonHandler();
    closeButton.addClickHandler(closeButtonHandler);
    closeButton.addMouseOverHandler(closeButtonHandler);
    closeButton.addMouseOutHandler(closeButtonHandler);
    root.add(closeButton);
    root.setCellWidth(closeButton, "18px");

    initWidget(root);
    setVisible(false);
  }

  /**
   * 构造指定级别消息的面板
   * 
   * @param level
   * @return 创建的面板
   */
  private VerticalPanel buildLevelPanel(int level) {
    HorizontalPanel frame = new HorizontalPanel();
    frame.setSpacing(2);
    levelsPanel.add(frame);

    String iconUrl = null, iconTitle = "";
    if (level == LEVEL_INFO) {
      iconUrl = IMAGE_INFO;
      iconTitle = "提示";
    } else if (level == LEVEL_WARNING) {
      iconUrl = IMAGE_WARNING;
      iconTitle = "警告";
    } else if (level == LEVEL_ERROR) {
      iconUrl = IMAGE_ERROR;
      iconTitle = "错误";
    }
    Image icon = new Image(iconUrl);
    icon.setTitle(iconTitle);
    frame.add(icon);

    VerticalPanel panel = new VerticalPanel();
    frame.add(panel);

    if (level == LEVEL_INFO)
      infoPanel = panel;
    else if (level == LEVEL_WARNING)
      warningPanel = panel;
    else if (level == LEVEL_ERROR)
      errorPanel = panel;

    return panel;
  }

  /**
   * 根据指定级别查询对应的面板，如果面板还没有被创建，则创建之
   * 
   * @param level
   * @return
   */
  private VerticalPanel getLevelPanel(int level) {
    if (level == LEVEL_INFO)
      return infoPanel != null ? infoPanel : buildLevelPanel(level);
    else if (level == LEVEL_WARNING)
      return warningPanel != null ? warningPanel : buildLevelPanel(level);
    else if (level == LEVEL_ERROR)
      return errorPanel != null ? errorPanel : buildLevelPanel(level);
    else
      return null;
  }

  /**
   * 添加一个提示消息
   * 
   * @param message
   *          消息内容
   */
  public void putInfoMessage(String message) {
    putInfoMessage(message, null);
  }

  /**
   * 添加一个提示消息
   * 
   * @param message
   *          消息内容
   * @param focusWidget
   *          消息对应的控件，点击消息后此控件会获得焦点。
   */
  public void putInfoMessage(String message, Focusable focusWidget) {
    putMessage(MessageRecord.newInfo(message, focusWidget));
  }

  /**
   * 添加一个警告消息
   * 
   * @param message
   *          消息内容
   */
  public void putWarningMessage(String message) {
    putWarningMessage(message, null);
  }

  /**
   * 添加一个警告消息
   * 
   * @param message
   *          消息内容
   * @param focusWidget
   *          消息对应的控件，点击消息后此控件会获得焦点。
   */
  public void putWarningMessage(String message, Focusable focusWidget) {
    putMessage(MessageRecord.newWarning(message, focusWidget));
  }

  /**
   * 添加一个错误消息
   * 
   * @param message
   *          消息内容
   */
  public void putErrorMessage(String message) {
    putErrorMessage(message, null);
  }

  /**
   * 添加一个错误消息
   * 
   * @param message
   *          消息内容
   * @param focusWidget
   *          消息对应的控件，点击消息后此控件会获得焦点。
   */
  public void putErrorMessage(String message, Focusable focusWidget) {
    putMessage(MessageRecord.newError(message, focusWidget));
  }

  /**
   * 添加消息
   * 
   * @param message
   *          消息内容
   * @param level
   *          消息的级别。取值参见名为“LEVEL_*”的常量。
   */
  public void putMessage(String message, int level) {
    putMessage(MessageRecord.newPut(message, level));
  }

  /**
   * 添加消息
   * 
   * @param message
   *          消息内容
   * @param level
   *          消息的级别。取值参见名为“LEVEL_*”的常量。
   * @param focusWidget
   *          消息对应的控件，点击消息后此控件会获得焦点。
   */
  public void putMessage(String message, int level, Focusable focusWidget) {
    putMessage(MessageRecord.newPut(message, level, focusWidget));
  }

  /**
   * 添加或覆盖消息，如果messageRecord.action为ACTION_REMOVE，也会删除相同id的消息
   * 
   * @param messageRecord
   */
  public void putMessage(final MessageRecord messageRecord) {
    // 查找相同id的消息
    Message existMessage = getMessageById(messageRecord.getId());

    if (MessageRecord.ACTION_PUT.equals(messageRecord.getAction())) {
      VerticalPanel levelPanel = getLevelPanel(messageRecord.getLevel());

      if (existMessage != null) {
        // 存在相同id的消息，更新之
        if (existMessage.getLevel() != messageRecord.getLevel()) {
          // 级别发生改变，需要把message.widget重新添加到对应的级别面板
          existMessage.getWidget().removeFromParent();
          levelPanel.add(existMessage.getWidget());
        }
        // 刷新message的内存数据和对应的界面显示
        existMessage.setMessageRecord(messageRecord);
      } else {
        // 不存在相同id的，则直接添加
        HTML html = new HTML();
        html.setStyleName(STYLENAME_MESSAGE);
        if (messageRecord.getFocusWidget() != null) {
          html.addStyleName(STYLENAME_MESSAGE_HASFOCUSWIDGET);
          html.addClickHandler(messageItemHandler);
          html.addMouseOverHandler(messageItemHandler);
          html.addMouseOutHandler(messageItemHandler);
        }
        Message newMessage = new Message(messageRecord, html);
        messages.add(newMessage);
        levelPanel.add(newMessage.getWidget());
      }
    } else {
      // 删除动作
      if (existMessage != null) {
        existMessage.getWidget().removeFromParent();
        messages.remove(existMessage);
      }
    }

    refresh();
  }

  /**
   * 添加、覆盖或删除一组消息
   * 
   * @param messageList
   *          元素为MessageRecord
   */
  public void putMessages(List/*MessageRecord*/messageList) {
    for (Iterator i = messageList.iterator(); i.hasNext();) {
      putMessage((MessageRecord) i.next());
    }
  }

  /**
   * 清除已显示的所有消息
   * 
   */
  public void clearMessages() {
    if (infoPanel != null)
      infoPanel.clear();
    if (warningPanel != null)
      warningPanel.clear();
    if (errorPanel != null)
      errorPanel.clear();
    messages.clear();
    setVisible(false);
  }

  /**
   * 刷新各级别面板的显示，以及整个面板的显示
   */
  private void refresh() {
    refreshLevelPanel(infoPanel);
    refreshLevelPanel(warningPanel);
    refreshLevelPanel(errorPanel);

    // 如果有消息可显示，则整个面板可见，否则隐藏整个面板
    setVisible(messages.size() > 0);
  }

  /**
   * 刷新级别面板的显示
   */
  private void refreshLevelPanel(VerticalPanel panel) {
    if (panel == null)
      return;

    if (panel.getWidgetCount() > 0) {
      if (panel.getParent().getParent() == null)
        levelsPanel.add(panel.getParent());
    } else {
      levelsPanel.remove(panel.getParent());
    }
  }

  /**
   * 如果没找到，则返回null
   * 
   * @param id
   * @return
   */
  private Message getMessageById(String id) {
    Message message = null;
    for (Iterator i = messages.iterator(); i.hasNext();) {
      Message m = (Message) i.next();
      if (m.getId() != null && m.getId().equals(id)) {
        message = m;
        break;
      }
    }
    return message;
  }

  /**
   * 关闭按钮事件处理
   * 
   * @author LiQi
   * 
   */
  private class CloseButtonHandler implements ClickHandler, MouseOverHandler, MouseOutHandler {

    public void onClick(ClickEvent event) {
      setVisible(false);
    }

    public void onMouseOver(MouseOverEvent event) {
      ((Image) event.getSource()).setVisibleRect(18, 0, 18, 18);
    }

    public void onMouseOut(MouseOutEvent event) {
      ((Image) event.getSource()).setVisibleRect(0, 0, 18, 18);
    }
  }

  /**
   * 消息条目事件处理
   * 
   * @author LiQi
   * 
   */
  private class MessageItemHandler implements ClickHandler, MouseOverHandler, MouseOutHandler {

    public void onClick(ClickEvent event) {
      Message message = getMessage((Widget) event.getSource());
      message.focusOnWidget();
    }

    private Message getMessage(Widget widget) {
      if (widget == null)
        return null;
      for (Iterator i = messages.iterator(); i.hasNext();) {
        Message message = (Message) i.next();
        if (widget.equals(message.getWidget()))
          return message;
      }
      return null;
    }

    public void onMouseOver(MouseOverEvent event) {
      ((Widget) event.getSource()).addStyleName(STYLENAME_MESSAGE_HASFOCUSWIDGET_HOVER);
    }

    public void onMouseOut(MouseOutEvent event) {
      ((Widget) event.getSource()).removeStyleName(STYLENAME_MESSAGE_HASFOCUSWIDGET_HOVER);
    }
  }

  /**
   * 在MessageRecord基础上加入消息对应的面板，用于内部界面控制
   * 
   * @author LiQi
   * 
   */
  private class Message {

    /** 对应的MessageRecord */
    private MessageRecord messageRecord;

    /** 显示此消息的控件 */
    private HTML widget;

    public Message(MessageRecord messageRecord, HTML widget) {
      this.widget = widget;
      setMessageRecord(messageRecord);
    }

    /**
     * 会自动刷新widget的内容显示
     * 
     * @param messageRecord
     */
    public void setMessageRecord(MessageRecord messageRecord) {
      this.messageRecord = messageRecord;
      if (widget != null)
        widget.setHTML(messageRecord.getMessage() + "&nbsp;");
    }

    public String getId() {
      return messageRecord.getId();
    }

    public String getMessage() {
      return messageRecord.getMessage();
    }

    public int getLevel() {
      return messageRecord.getLevel();
    }

    public String getAction() {
      return messageRecord.getAction();
    }

    public Focusable getFocusWidget() {
      return messageRecord.getFocusWidget();
    }

    public void focusOnWidget() {
      messageRecord.focusOnWidget();
    }

    public HTML getWidget() {
      return widget;
    }

  }

}
